package com.kunyi.web.service.file.core.handel;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.crypto.digest.MD5;
import com.kunyi.platform.redis.RedisService;
import com.kunyi.platform.tool.api.JsonResult;
import com.kunyi.platform.tool.util.KyAssertUtil;
import com.kunyi.web.service.file.core.config.FileConfig;
import com.kunyi.web.service.file.core.constant.FileRedisLockConstant;
import com.kunyi.web.service.file.core.enums.KunyiRepositoryTypeEnum;
import com.kunyi.web.service.file.core.handel.Impl.KunyiLocalRepository;
import com.kunyi.web.service.file.core.handel.Impl.KunyiMinioRepository;
import com.kunyi.web.service.file.core.handel.Impl.KunyiOssRepository;
import com.kunyi.web.service.file.service.IUploadService;
import com.kunyi.web.serviceapi.system.api.IConfigClient;
import com.kunyi.web.serviceapi.system.entity.FileDefaultInfoDto;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.Iterator;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @ClassName KunyiFileHandelContxt
 * @Description 自动选择文件操作类
 * @Author zhenguo.zhuang
 * @Date 2024/3/13 10:55
 * @Version 1.0
 */
@Slf4j
@Component
public class KunyiFileHandelContxt {
    @Autowired
    private IUploadService uploadService;

    @Autowired
    private FileConfig fileConfig;

    @Resource
    IConfigClient iConfigClient;

    @Autowired
    RedisService redisService;


    /**
     * 链接对象集合
     */
    private    Map<String,KunyiRepository>  kunyiRepositoryMap = new ConcurrentHashMap<>();

    /**
     * @author: zhenguo.zhuang
     * @Description 匹配对应的文件处理类
     * @Date 13:24 2024/3/13
     * @Param :
     * @return KunyiRepository
     **/
    public  KunyiRepository handel()  {
            log.info("获取文件处理类");
            KunyiRepository repository=null;
            //第一步:读取redis的链接信息
            JsonResult<FileDefaultInfoDto> defaultFileInfo = iConfigClient.getDefaultFileInfo();
            FileDefaultInfoDto fileInfoData = defaultFileInfo.getData();
            log.info("文件默认配置为：{}",fileInfoData);
            //第二步：没有默认的就用local
            //map中的key
            String repositoryKey=null;
            //文件类型
            String fileType=null;
            //登录信息
            if (ObjectUtil.isNull(fileInfoData)){
                repositoryKey=KunyiRepositoryTypeEnum.LOCAL.getCode();
                fileType=KunyiRepositoryTypeEnum.LOCAL.getCode();
            }else {
                fileType = KunyiRepositoryTypeEnum.getCode(fileInfoData.getType());
                //第二步：匹配对应的文件处理类
                repositoryKey = generateMd5(fileInfoData);
            }
            //10个线程同时进入，如果配置信息都一样，只能初始一个实例对象，所以生成实例对象这一块需要加锁
            RLock lock = redisService.lock(FileRedisLockConstant.LOCK_INITIAL_KEY);
            try {
                //第三步： 不存在就创建出具体的bean
                if(!kunyiRepositoryMap.containsKey(repositoryKey)) {
                    repository = loginFileRepository(fileInfoData, fileType);
                    //删除第一个元素
                    if (kunyiRepositoryMap.size()>9){
                        Iterator<String> iterator = kunyiRepositoryMap.keySet().iterator();
                        if (iterator.hasNext()){
                            iterator.next();
                            iterator.remove();
                        }
                    }
                    kunyiRepositoryMap.put(repositoryKey,repository);
                    return repository;
                }
            }catch (Exception e){
                e.printStackTrace();
            }finally {
                redisService.unLock(lock);
            }
            // 第四步：存在即取出具体的bean返回并且   //去除末尾淘汰机制，不然锁的粒度太大，影响效率
            repository = kunyiRepositoryMap.get(repositoryKey);
            log.info("当前文件处理bean为：{}",repository);
            return repository;

    }


    /**
     * @author: zhenguo.zhuang
     * @Description 初始化bean
     * @Date 9:48 2024/3/15
     * @Param loginInfo:
	 * @Param type:
     * @return void
     **/
    public KunyiRepository loginFileRepository(FileDefaultInfoDto fileDefaultInfoDto, String type){
        KunyiRepository bean=null;
        KunyiRepositoryTypeEnum typeEnum = KunyiRepositoryTypeEnum.valueOf(type.toUpperCase());
        FileLoginParams loginParams = new FileLoginParams();
        loginParams.setLoginInfo(fileDefaultInfoDto);
        loginParams.setService(uploadService);
        loginParams.setUrl(fileConfig.getUrl());
        loginParams.setRedisService(redisService);
        loginParams.setLinuxRootPath(fileConfig.getLinuxRootPath());
        loginParams.setWindowsRootPath(fileConfig.getWindowsRootPath());
        switch (typeEnum){
            case OSS:
                KunyiOssRepository kunyiOssRepository = new KunyiOssRepository();
                boolean login = kunyiOssRepository.login(loginParams);
                KyAssertUtil.isTrue(login, "初始化错误");
                bean=kunyiOssRepository;
                break;
            case LOCAL:
                KunyiLocalRepository kunyiLocalRepository = new KunyiLocalRepository();
                Boolean loginLocal= kunyiLocalRepository.login(loginParams);
                KyAssertUtil.isTrue(loginLocal, "初始化错误");
                bean=kunyiLocalRepository;
                break;
            case MINIO:
                KunyiMinioRepository kunyiMinioRepository = new KunyiMinioRepository();
                boolean loginMinio = kunyiMinioRepository.login(loginParams);
                KyAssertUtil.isTrue(loginMinio, "初始化错误");
                bean=kunyiMinioRepository;
                break;
            default:
                KyAssertUtil.isTrue(true, "初始化错误");
                break;
        }
        return bean;
    }

    /**
     * @author: zhenguo.zhuang
     * @Description 生成MD5值
     * @Date 14:11 2024/3/15
     * @Param loginInfo:
     * @return String
     **/
    private String generateMd5(FileDefaultInfoDto fileInfoData){
        return MD5.create().digestHex(fileInfoData.getEndpoint()+
                fileInfoData.getAccessKey()+
                fileInfoData.getAccessSecret()+
                fileInfoData.getDirectory()+
                fileInfoData.getBucketName());
    }



}
